package com.senriot.quickup.service

import com.fasterxml.jackson.databind.ObjectMapper
import com.senriot.cloud.aliyun.DeviceManager
import com.senriot.cloud.common.AbstractService
import com.senriot.quickup.domain.Ad
import com.senriot.quickup.domain.AdSchedule
import com.senriot.quickup.domain.DeviceMessage
import com.senriot.quickup.domain.QAdSchedule
import com.senriot.quickup.domain.enums.MessageLogType
import com.senriot.quickup.repository.AdScheduleRepository
import com.senriot.quickup.repository.DeviceRepository
import com.senriot.quickup.service.dto.AdScheduleDTO
import com.senriot.quickup.service.mapper.AdScheduleMapper
import io.reactivex.Observable
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import reactor.core.Reactor
import reactor.event.Event
import java.nio.charset.Charset
import java.time.LocalDateTime
import java.util.*
import java.util.concurrent.TimeUnit
import javax.annotation.PostConstruct

@Service
@Transactional
class AdScheduleService(
    private val reactor: Reactor
) : AbstractService<AdSchedule, Long, AdScheduleDTO, AdScheduleRepository, AdScheduleMapper>()
{
    @PostConstruct
    fun init()
    {
        reactor.on<Event<DeviceMessage>> { event ->
            if (event.data.msgType == MessageLogType.Status)
            {
                if (event.data.payload?.get("status") == "online")
                {
                    Observable.timer(3000,TimeUnit.MILLISECONDS).subscribe {
                        updateDeviceAds(listOf(event.data.device!!.id!!))
                    }
                }
            }
        }
    }


    @Autowired
    private lateinit var om: ObjectMapper

    @Qualifier("deviceRepository")
    @Autowired
    private lateinit var deviceRepository: DeviceRepository

    @Autowired private lateinit var deviceManager: DeviceManager

    @Value("\${seri.iot.productKey:a1DRsxixYff}")
    private var productKey = ""

    @Transactional(readOnly = true)
    fun getAdByDevice(deviceId: String): MutableList<Ad>
    {
        val q = QAdSchedule.adSchedule
        val ads = repository.findAll(
            q.devices.any().deviceId.eq(deviceId)
                .and(q.startDate.loe(LocalDateTime.now()))
                .and(q.endDate.goe(LocalDateTime.now()))
        )

        val result = mutableListOf<Ad>()
        ads.forEach {
            if (it.ads != null)
                result.addAll(it.ads!!)
        }

        return result
    }

    /**
     * 推送广告
     * @param deviceIds List<String>?
     */
    fun updateDeviceAds(deviceIds: List<String>?)
    {
        deviceIds?.let { list ->
            deviceRepository.findAllById(list).forEach {
                val ads = getAdByDevice(it.deviceId!!)
                if (ads.isNotEmpty())
                {
                    val topic = "/a1P1viTT1xx/${it.deviceId}/user/ad/post"
                    val str = om.writeValueAsString(ads)
                    val res = deviceManager.pubMessage(
                        productKey,
                        topic,
                        Base64.getEncoder().encodeToString(str.toByteArray(Charset.defaultCharset())), 1
                    )
                    log.info("消息发送 $res")
                }
            }
        }
    }

    override fun update(dto: AdScheduleDTO): Optional<AdScheduleDTO>
    {
        val result = super.update(dto)
        updateDeviceAds(dto.devices)
        return result
    }

    override fun create(dto: AdScheduleDTO): AdScheduleDTO
    {
        val result = super.create(dto)
        updateDeviceAds(dto.devices)
        return result
    }
}
